#pragma once
#include <iostream>
#include <memory>
#include "Socket.hpp"
#include "InetAddr.hpp"
#include <jsoncpp/json/json.h>
#include <functional>
using namespace SocketModule;
//实现一个自定义的网络版本计算器
//约定好各个字段的含义，本质就是约定好协议
//client->serve
class Request
{
    //都需要序列和反序列化接口
public:
    Request(){}
    Request(int x,int y,char oper):_x(x),_y(y),_oper(oper){}
    //序列化，这里的数据是需要发送给服务器的
    std::string Serialization()
    {
        Json::Value root;
        root["x"]=_x;
        root["y"]=_y;
        root["oper"]=_oper;
        Json::FastWriter write;
        std::string s=write.write(root);
        return s;
    }
    bool DeSerialization(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok=reader.parse(in,root);
        if(!ok)
            return ok;
        _x=root["x"].asInt();
        _y=root["y"].asInt();
        _oper=root["oper"].asInt();

        return ok;
    }
    int GetX(){return _x;}
    int GetY(){return _y;}
    char GetOper(){return _oper;}
    ~Request(){}
private:
    int _x;
    int _y;
    char _oper;
};

//serve->client
class Response
{
//只有运算结果，无法区分应答是否计算成功
public:
    Response(){}
    Response(int code):_code(code){}
    Response(int result,int code):_result(result),_code(code){}
    ~Response(){}
    std::string Serialization()
    {
        Json::Value root;
        root["result"]=_result;
        root["code"]=_code;
        Json::FastWriter write;
        std::string s=write.write(root);
        return s;
    }
    bool DeSerialization(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok=reader.parse(in,root);
        if(!ok)
            return ok;
        _result=root["result"].asInt();
        _code=root["code"].asInt();

        return ok;
    }
    void ShowResult()
    {
        std::cout<<"计算的结果是: " << _result << "["<<_code<<"]"<<std::endl;
    }
    void Setres(int _res){_result=_res;}
    void Setcode(int code){_code=code;}
private:
    int _result;
    int _code;//0表示计算正确
};

using func_t=std::function<Response(Request&req)>;
class Protocol
{
public:
    Protocol(){}
    Protocol(func_t func):_func(func){}
    //TCp是面向字节流的，每次从缓冲区中读数据可能会读的不是一条完整的报文，可能是一条或者多条，又或者不足一条
    //为了解决这种情况，我们可以在一条报文的前后增加一些标志位来标识报文的开头和结束以及报文长度
    //增加了报头，到时候还需要解报，所以需要设计成易于封装和解封装
    //增加两个接口，一个用于封装，一个用于解封装
    //下面约定20\r\n{"x":10,"y":20:"oper":"+"}\r\n是一条完整的报文
    const std::string sep="\r\n";
    std::string EncauplationMessage(std::string Message)
    {
        //封装报文
        size_t len_message=Message.size();
        return std::to_string(len_message)+sep+Message+sep;
    }
    //读取到的一条报文有多种可能，我们只需要做的就是提取一条有效的报文，提取不到有效报文也不能返回报文，
    //所以函数设计成返回bool比较合适,参数需要一个被解封装的报文，还有读取成功时返回的一条报文

    //一条完整的报文
    //20\r\n{"x":10,"y":20:"oper":"+"}\r\n
    //参数设计成string*还是string，看具体实现在修改吧,
    //参数设计成string*，因为这些数据都是在缓冲区里的，如果想要修改必须传址，传值不会对package有影响
    //自然这个函数的逻辑实现也就没有作用
    //通过telent+ip连接
    bool ReleaseEncauplationMessage(std::string& Message,std::string* package)
    {
        //查找sep的位置，如果sep不存在，一定不是一条完整的报文
        size_t sep_position=Message.find(sep);
        if(sep_position==std::string::npos)
            return false;
        //找报文长度
        std::string Message_len=Message.substr(0,sep_position);
        //读取并计算一条完整报文应有的长度
        int target_len=std::stoi(Message_len)+Message_len.size()+sep.size()*2;
        //实际读到的报文长度如果还没有应有长度大就证明没有读到一条完整的报文
        if(target_len>Message.size())
            return false;
        
        //返回读到的一条报文
        *package=Message.substr(sep_position+sep.size(),std::stoi(Message_len));
        //删除刚才读到的报文
        Message.erase(0,target_len);
        return true;
    }
    //一直死循环打印accept unsuccess不是这里的问题
    //是Start函数里处理sockfd的问题
    void GetRequest(std::shared_ptr<Socket>&sock,InetAddr& client)
    {
        std::string ClientMessage;
        while(true)
        {
            //1.先接收来自客户端的发送消息
            int ReadByteSize=sock->Recv(&ClientMessage);
            if(ReadByteSize>0)
            {
                // std::cout<<"----------serve接收的字符串---------"<<std::endl;
                // std::cout<<ClientMessage<<std::endl;
                // std::cout<<"--------------------------------"<<std::endl;
                // 2.发过来的是经过序列化的数据，需要先进行解报
                // std::cout<<"ClientMessage:\n"<<ClientMessage<<std::endl;//测试用的
                std::string REmessage;
                while(ReleaseEncauplationMessage(ClientMessage,&REmessage))
                {
                
                    // std::cout<<"----------serve反序列化后的字符串---------"<<std::endl;
                    // std::cout<<REmessage<<std::endl;
                    // std::cout<<"--------------------------------"<<std::endl;

                    // std::cout<<"----------serve接收的字符串---------"<<std::endl;
                    // std::cout<<ClientMessage<<std::endl;
                    // std::cout<<"--------------------------------"<<std::endl;


                    // if(!ok)//没有读到完整的一条报文
                    //     continue;
                    //3.一定读到完整的报文了，就该解析数据了，拿到的是{"x":10,"y":20:"oper":"+"}这样的数据，需要解析json串
                    Request AnalysisJson;
                    AnalysisJson.DeSerialization(REmessage);
                    LOG(INFO)<<"请求是 "<<REmessage;
                    //解析数据后需要做出响应，给出响应需要的参数，就要在request中增加访问私有属性的接口了
                    //4.使用回调函数来处理接收到的数据
                    Response RecvEcho=_func(AnalysisJson);
                    //5.处理完成后再序列化
                    std::string SerialRecvEcho=RecvEcho.Serialization();
                    //6.序列化的数据再封装报头
                    std::string EncauplationJson=EncauplationMessage(SerialRecvEcho);
                    //7.发送封装好报头的数据
                    sock->Send(EncauplationJson);
                }
            }
            else if(ReadByteSize==0)
            {
                //说明写端关闭了
                LOG(WARNING)<<"ClientIP: "<<client.StringAddrIP()<<" QUIT";
                break;
            }
            else
            {
                LOG(WARNING)<<"ClientIP: "<<client.StringAddrIP()<<" recv error";
                break;
            }
        }
    }
    std::string BuildRequestString(int x,int y,char oper)
    {
        //1.序列化字符串
        Request req(x,y,oper);
        std::string req_str=req.Serialization();
        //2.封装字符串
        // std::cout<<"------req_str--------"<<std::endl;
        // std::cout<<req_str<<std::endl;
        // std::cout<<"---------------------"<<std::endl;
        return EncauplationMessage(req_str);
    }
    bool GetResponse(std::unique_ptr<Socket>& client,std::string& res_buffer,Response* res)
    {
        while(true)
        {
            //先通过sockfd获取request
            int n=client->Recv(&res_buffer);
            if(n>0)
            {
                //响应的一定是一个序列化的串，需要先解报
                std::string REMessage;
                while(ReleaseEncauplationMessage(res_buffer,&REMessage))
                {
                    // std::cout<<"------解报后的字符串REMessage--------------"<<std::endl;
                    // std::cout<<REMessage<<std::endl;
                    // std::cout<<"-----------------------------------"<<std::endl;
                    // if(!ok)
                    //     continue;
                    res->DeSerialization(REMessage);
                    // std::cout<<"------反序列化后的字符串REMessage--------------"<<std::endl;
                    // std::cout<<REMessage<<std::endl;
                    // std::cout<<"-----------------------------------"<<std::endl;
                    return true;
                }
            }
            else if(n==0)
            {
                LOG(WARNING)<<"Serve"<<" QUIT";
                // break;
                return false;
            }
            else
            {
                LOG(WARNING)<<"Serve Recv"<<" error";
                // break;
                return false;
            }
        }
    }
    ~Protocol(){}
private:
    //多线程使用临时变量
    // Request _requ;
    // Response _resp;
    func_t _func;
};